#include <std.h> //Standard functions
#include <error.h> //Errors
#include <cache.h>
#include <memory.h> //Mem allocations


/*********************Kernel Function File*********************--cache.h*/

/*As long as the scheduler structs are not accessed we are safe with spin_locks..*/

/*Allocate a set of cache block*/

#define clear_cache(cache) memset(cache,NULL,sizeof(struct cache_block)*cache->cache_size)

struct cache_block *init_cache(u32 cache_size)
{
	struct cache_block *cache;
	spin_lock_t c;
	acquire_spin_lock(&c);
	cache=(struct cache_block *)get_mem(sizeof(struct cache_block)*cache_size);
	cache->cache_size=cache_size;
	clear_cache(cache);
	release_spin_lock(&c);
	return cache;
}

/*Find the least used cache block to remove*/
int renovate_cache(struct cache_block *cache)
{
	int i,l=0,lc=0;
	sane(cache==NULL,"CAche!");
	for(i=0;i<cache->cache_size;i++)	{
		if(cache[i].flag>l)	{
			l=cache[i].flag;
			lc=i;
		}
	}
	cache[lc].flag=0;
	return NULL;
}

/*Check caches for a hit*/

#define nice_cache(cache,i) cache[i].flag++

int check_cache(struct cache_block *cache,u32 tag)
{
	int i;
	sane(cache==NULL,"CAche!");
	for(i=(tag%cache->cache_size);i<cache->cache_size;i++)	{
		if(cache[i].tag==tag && cache[i].flag>0)	{
			nice_cache(cache,i);
			return SUCCESS;
		}
	}
	renovate_cache(cache);
	return FAILED;
}

int get_free_cache(struct cache_block *cache,int i)
{
	while(cache[i].flag>0 && i<cache->cache_size)
		i++;
	return i;
}

/*Add a buffer to the cache*/
int add_cache(struct cache_block *cache,u8 *buf,u32 tag)
{
	int i;
	sane(cache==NULL || buf==NULL,"CAche!");
	i=tag%cache->cache_size;
	i=get_free_cache(cache,i);
	if(i<cache->cache_size)	{
		memcpy(cache[i].block,buf,BLK_SIZE);
		cache[i].tag=tag;
		nice_cache(cache,i);
		return SUCCESS;
	}
	return FAILED;
}
